package com.xlf.service.base.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xlf.common.auth.util.SecurityUtils;
import com.xlf.common.core.constant.Constants;
import com.xlf.common.core.exception.BizException;
import com.xlf.common.core.pojo.mode.R;
import com.xlf.common.core.pojo.vo.UserVO;
import com.xlf.common.core.util.ServletUtils;
import com.xlf.common.core.util.StringUtils;
import com.xlf.pojo.base.Difficulty;
import com.xlf.pojo.base.Judge;
import com.xlf.pojo.base.Problem;
import com.xlf.pojo.base.SysUserExtend;
import com.xlf.pojo.system.SysUser;
import com.xlf.service.base.mapper.DifficultyMapper;
import com.xlf.service.base.mapper.JudgeMapper;
import com.xlf.service.base.mapper.ProblemMapper;
import com.xlf.service.base.pojo.dto.RegisterDTO;
import com.xlf.service.base.pojo.vo.RecentlyACProblemVO;
import com.xlf.service.base.pojo.vo.UserInfoDTO;
import com.xlf.service.base.pojo.vo.UserInfoVO;
import com.xlf.service.base.pojo.vo.UserJudgeInfoVO;
import com.xlf.service.base.service.SysUserExtendService;
import com.xlf.service.base.mapper.SysUserExtendMapper;
import com.xlf.service.base.service.impl.validate.AccountValidator;
import com.xlf.service.system.service.impl.CommonUserVOService;
import jodd.typeconverter.Convert;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author 小新
* @description 针对表【sys_user_extend】的数据库操作Service实现
* @createDate 2024-01-07 11:06:09
*/
@Service
public class SysUserExtendServiceImpl extends ServiceImpl<SysUserExtendMapper, SysUserExtend>
    implements SysUserExtendService{


    @Autowired
    CommonUserVOService commonUserVOService;

    @Resource
    DifficultyMapper difficultyMapper;

    @Resource
    ProblemMapper problemMapper;

    @Resource
    JudgeMapper judgeMapper;

    @Resource
    Redisson redisson;


    @Override
    public UserInfoVO getUserInfoVO() {

        Long userId = Convert.toLong(ServletUtils.getParameter("userId"));

        if(userId == null)
            userId = (Long) SecurityUtils.getUserId();


        UserVO userInfo = commonUserVOService.getUserInfo(userId);

        if(userInfo == null)
            throw new BizException("用户不存在！");

        UserInfoVO userInfoVO = UserInfoVO.builder()
                .userName(userInfo.getUserName())
                .sex(userInfo.getSex())
                .avatar(userInfo.getAvatar())
                .nickName(userInfo.getNickName()).build();
        SysUserExtend userExtend = getById(userInfo.getUserId());
        if(userExtend != null){
            userInfoVO.setBg(userExtend.getBg());
            userInfoVO.setSign(userExtend.getSign());
        }
        return userInfoVO;
    }


    @Override
    public void updateUserInfo(UserInfoDTO userInfodto) {



        SysUser sysUser = SysUser.builder()
                .userId((Long) SecurityUtils.getUserId())
                .nickName(userInfodto.getNickName())
                .avatar(userInfodto.getAvatar())
                .sex(userInfodto.getSex())
                .build();



        if(!commonUserVOService.updateUserInfo(sysUser))
            throw new BizException("更新用户信息失败！");

        SysUserExtend userExtend = new SysUserExtend();
        userExtend.setId(sysUser.getUserId());
        userExtend.setSign(userInfodto.getSign());
        userExtend.setBg(userExtend.getBg());
        if(!saveOrUpdate(userExtend))
            throw new BizException("更新用户信息失败！");
    }


    @Override
    public ArrayList<UserJudgeInfoVO> getJudgeInfo() {

        Long userId = Convert.toLong(ServletUtils.getParameter("userId"));

        if(userId == null)
            userId = (Long) SecurityUtils.getUserId();

        List<Difficulty> list = difficultyMapper.selectList(new LambdaQueryWrapper<Difficulty>()
                        .select(Difficulty::getId,Difficulty::getName)
                .eq(Difficulty::getStatus, Constants.NORMAL));

        ArrayList<UserJudgeInfoVO> userJudgeInfoVOS = new ArrayList<>();
        if(StringUtils.isEmpty(list))
            return new ArrayList<>();


        Long finalUserId = userId;
        list.forEach(item -> {
            UserJudgeInfoVO userJudgeInfoVO = new UserJudgeInfoVO();
            userJudgeInfoVO.setDifficultyName(item.getName());
            List<Problem> problemList = problemMapper.selectList(new LambdaQueryWrapper<Problem>()
                    .select(Problem::getId)
                    .eq(Problem::getDifficultyId, item.getId())
                    .eq(Problem::getStatus, Constants.NORMAL));
            if(StringUtils.isEmpty(problemList)){
                userJudgeInfoVO.setProblemNum(0);
                userJudgeInfoVO.setAcNum(0);
            }else {
                Set<Long> problemIds = problemList.stream().map(Problem::getId).collect(Collectors.toSet());
                userJudgeInfoVO.setProblemNum(problemIds.size());
                List<Judge> judges = judgeMapper.selectList(new LambdaQueryWrapper<Judge>()
                        .select(Judge::getPid)
                        .eq(Judge::getUserId, finalUserId)
                        .eq(Judge::getStatus, com.xlf.pojo.constant.Constants.Judge.STATUS_ACCEPTED)
                        .in(Judge::getPid, problemIds));
                if(StringUtils.isEmpty(judges)) {
                    userJudgeInfoVO.setAcNum(0);
                }
                else {
                    userJudgeInfoVO.setAcNum(judges.stream().map(Judge::getPid)
                            .collect(Collectors.toSet()).size());

                }
            }
            userJudgeInfoVOS.add(userJudgeInfoVO);

        });

        return userJudgeInfoVOS;

    }

    /**
     *
     * @return  key : yyyy-MM-dd : value : num
     */
    @Override
    public Map<String, Integer> getHeatmap() {

        Long userId = Convert.toLong(ServletUtils.getParameter("userId"));

        if(userId == null)
            userId = (Long) SecurityUtils.getUserId();

        Date date = new Date();
        List<Judge> judges = judgeMapper.selectList(new LambdaQueryWrapper<Judge>()
                .select(Judge::getSubmitTime)
                .eq(Judge::getUserId,userId)
                .ge(Judge::getSubmitTime, DateUtil.offsetMonth(date, -12))
                .le(Judge::getSubmitTime, date));

        if(StringUtils.isEmpty(judges))
            return new HashMap<>();
        HashMap<String, Integer> heatMap = new HashMap<>();
        judges.forEach(judge -> {
            Date submitTime = judge.getSubmitTime();
            String dateStr = DateUtil.format(submitTime, "yyyy-MM-dd");
            heatMap.merge(dateStr, 1, Integer::sum);
        });

        return heatMap;
    }


    @Override
    public List<RecentlyACProblemVO> getRecentlyACProblem() {

        Long userId = Convert.toLong(ServletUtils.getParameter("userId"));

        if(userId == null)
            userId = (Long) SecurityUtils.getUserId();


        List<Judge> judges = judgeMapper.selectList(new LambdaQueryWrapper<Judge>()
                .select(Judge::getPid,Judge::getSubmitTime)
                .eq(Judge::getUserId, userId)
                .eq(Judge::getStatus, com.xlf.pojo.constant.Constants.Judge.STATUS_ACCEPTED)
                .groupBy(Judge::getPid)
                .orderByAsc(Judge::getSubmitTime)
                .last("limit 10"));
        if(StringUtils.isEmpty(judges))
            return new ArrayList<>();

        List<Problem> problemList = problemMapper.selectList(new LambdaQueryWrapper<Problem>()
                        .select(Problem::getId,Problem::getProblemId,Problem::getTitle)
                .in(Problem::getId, judges.stream().map(Judge::getPid).collect(Collectors.toSet()))
                .eq(Problem::getAuth, com.xlf.pojo.constant.Constants.ProblemAuth.PUBLIC)
                .eq(Problem::getStatus, Constants.NORMAL));

        ArrayList<RecentlyACProblemVO> recentlyACProblemVOS = new ArrayList<>(10);

        if(StringUtils.isEmpty(problemList))
            return recentlyACProblemVOS;

        Map<Long, Problem> problemMap = problemList.stream().collect(Collectors.toMap(problem -> problem.getId(), problem -> problem));
        judges.forEach(item -> {
            if(problemMap.containsKey(item.getPid())){
                Problem problem = problemMap.get(item.getPid());
                RecentlyACProblemVO problemVO = RecentlyACProblemVO.builder()
                        .id(problem.getId())
                        .problemId(problem.getProblemId())
                        .title(problem.getTitle())
                        .submitDate(item.getSubmitTime()).build();
                recentlyACProblemVOS.add(problemVO);

            }
        });

        return recentlyACProblemVOS;
    }

    @Override
    public void register(RegisterDTO registerDTO) {

        AccountValidator.isValidUsername(registerDTO.getUserName());
        AccountValidator.isValidPassword(registerDTO.getPassword());

        UserVO userVO = commonUserVOService.getUserInfoByUserName(registerDTO.getUserName());

       if(StringUtils.isNotNull(userVO))
            throw new BizException("账号已存在！");

        SysUser sysUser = new SysUser();
        sysUser.setPassword(registerDTO.getPassword());
        sysUser.setNickName(registerDTO.getUserName());
        sysUser.setUserName(registerDTO.getUserName());
        sysUser.setCreateTime(new Date());
        sysUser.setAvatar("http://image.xlfdeblog.top/blog/ea33e31dd6fb63e7a2578553f1cd24fd.png");
        Long[] roles = {7L};
        sysUser.setRoleIds(roles);

        RLock lock = redisson.getLock(AccountValidator.registerLock + registerDTO.getUserName());

        if(!lock.tryLock())
            throw new BizException("操作频繁，请稍等重试！");

        try {
            commonUserVOService.register(sysUser);
        } finally {
            lock.unlock();
        }



    }

}




